package cn.topevery.garden.dal.logic.event;


import cn.hutool.core.bean.BeanUtil;
import cn.topevery.garden.dal.dao.event.EventInfoDao;
import cn.topevery.garden.dal.dao.event.EventInfoFileDao;
import cn.topevery.garden.dal.logic.ParkCompanyLogic;
import cn.topevery.garden.dal.util.DeptUtil;
import cn.topevery.garden.dal.util.WorkFlowUtil;
import cn.topevery.garden.entity.bo.EventInfoBo;
import cn.topevery.garden.entity.dto.event.EventDelayApplyDTO;
import cn.topevery.garden.entity.dto.event.EventDelayAuditDTO;
import cn.topevery.garden.entity.dto.event.EventInfoDTO;
import cn.topevery.garden.entity.dto.event.SerialNoDTO;
import cn.topevery.garden.entity.dto.flow.BackActPara;
import cn.topevery.garden.entity.dto.flow.NextActivityTarget;
import cn.topevery.garden.entity.dto.flow.SendActPara;
import cn.topevery.garden.entity.po.event.EventDelayApply;
import cn.topevery.garden.entity.po.event.EventInfo;
import cn.topevery.garden.entity.po.event.EventInfoFile;
import cn.topevery.garden.entity.query.CompanyQuery;
import cn.topevery.garden.entity.query.EventDelayApplyQuery;
import cn.topevery.garden.entity.query.EventInfoQuery;
import cn.topevery.garden.entity.vo.event.ActivityInstanceVO;
import cn.topevery.garden.entity.vo.event.EventDelayApplyVO;
import cn.topevery.garden.entity.vo.event.EventInfoVO;
import cn.topevery.garden.framework.base.BaseLogic;
import cn.topevery.garden.framework.config.EventFlowConfig;
import com.github.dozermapper.core.Mapper;
import hw.topevery.af.entity.bo.ActivityInstanceBo;
import hw.topevery.af.entity.bo.RuntimeActivity;
import hw.topevery.af.entity.enums.ReceiveTypeEnum;
import hw.topevery.af.entity.po.ActivityInstance;
import hw.topevery.af.entity.vo.*;
import hw.topevery.af.runtime.WorkflowRuntimeManager;
import hw.topevery.basis.dal.logic.SysCompanyLogic;
import hw.topevery.basis.dal.logic.SysClassExtLogic;
import hw.topevery.basis.dal.logic.SysDeptInTreeLogic;
import hw.topevery.basis.dal.logic.SysDeptLogic;
import hw.topevery.basis.entity.dto.DeptDto;
import hw.topevery.basis.entity.dto.DeptInTreeDto;
import hw.topevery.basis.entity.model.DeptTree;
import hw.topevery.basis.entity.po.SysCompany;
import hw.topevery.basis.entity.po.SysUser;
import hw.topevery.basis.runtime.UserRuntime;
import hw.topevery.framework.DataFillHelper;
import hw.topevery.framework.GeometryHelper;
import hw.topevery.framework.SystemConst;
import hw.topevery.framework.Utility;
import hw.topevery.framework.db.base.BaseEntityDao;
import hw.topevery.framework.db.entity.DataPager;
import hw.topevery.framework.dto.PointDto;
import hw.topevery.framework.entity.KeyValue;
import hw.topevery.framework.map.CoordinateTransHelper;
import hw.topevery.framework.web.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 案件表
 *
 * @author code-generate
 * @date 2022-08-23
 */
@Service
@Slf4j
public class EventInfoLogic extends BaseLogic<EventInfo> {
    @Autowired
    EventInfoDao eventInfoDao;

    @Autowired
    EventInfoFileDao eventInfoFileDao;

    @Autowired
    private Mapper mapper;

    @Autowired
    private SysClassExtLogic sysClassExtLogic;

    @Autowired
    private SysDeptInTreeLogic sysDeptInTreeLogic;

    @Autowired
    private WorkFlowUtil workFlowUtil;

    @Autowired
    private WorkflowRuntimeManager workflowRuntimeManager;

    @Autowired
    private SysDeptLogic deptLogic;

    @Autowired
    private DeptUtil deptUtil;

    @Autowired
    private SysCompanyLogic companyLogic;

    @Autowired
    private ParkCompanyLogic parkCompanyLogic;

    @Autowired
    private EventDelayApplyLogic eventDelayApplyLogic;

    @Override
    public BaseEntityDao<EventInfo, Integer> getDao() {
        return eventInfoDao;
    }


    /**
     * 获取列表
     *
     * @param query
     */
    public DataPager<EventInfoVO> listPage(EventInfoQuery query, SysUser user) {
        return eventInfoDao.listPage(query, user, null);
    }

    /**
     * 根据自增id批量删除
     *
     * @param ids
     */
    public void deleteBatchById(String userId, Integer[] ids) {
        eventInfoDao.delete(userId, ids);
    }

    /**
     * 根据自增id保存或者更新
     *
     * @param eventInfo 实体
     */
    public void saveOrUpdate(String userId, EventInfo eventInfo) {
        eventInfoDao.saveOrUpdate(userId, eventInfo);
    }

    /**
     * 根据自定义列值来获取对象
     */
    public EventInfo getEntityByColumn(String key, String value) {
        return eventInfoDao.getEntityByColumn(key, value);
    }

    @Transactional
    public JsonResult<?> saveEvent(SysUser user, EventInfoDTO dto) {
        try {
            dto.setEvtId(UUID.randomUUID().toString().toUpperCase())
                    .setReportId(user.userId)
                    .setReportDate(LocalDateTime.now())
                    .setReportName(user.userName)
                    .setReportDeptId(user.deptId)
                    .setLastDeptId("835B6E1F-D9E7-42DB-A362-1317D8DBF8FB")//案件最终处理部门(市)
                    .setIsKf((byte) 0);//新上报案件暂不扣分，结案后再予扣除
            if (dto.getTypeList().contains("1B3E5DD2-7DFE-4C0B-A546-C6076CCDF6BB") &&
                    (StringUtils.isBlank(dto.getExecutorId()) || StringUtils.isBlank(dto.getExecutor()))) {
                return JsonResult.error("其他任务类型案件需直接指定执行人！");
            }
            if (dto.getGeoX() != null && dto.getGeoY() != null) {
                PointDto pointDto = CoordinateTransHelper.gcjDecrypt(dto.getGeoX(), dto.getGeoY());
                PointDto baidu = CoordinateTransHelper.wgs84Bd09(pointDto.getLng(), pointDto.getLat());
                dto.setLngBd09(baidu.getLng());
                dto.setLatBd09(baidu.getLat());
            }
            if (dto.getLngBd09() != null && dto.getLatBd09() != null) {
                PointDto pointDto = CoordinateTransHelper.bdDecrypt(dto.getLngBd09(), dto.getLatBd09());
                dto.setGeoX(pointDto.getLng());
                dto.setGeoY(pointDto.getLat());
            }
            if (dto.getGeoX() != null && dto.getGeoY() != null) {
                GeometryHelper.MapPoint mapPoint = GeometryHelper.xyToMercator(dto.getGeoX(), dto.getGeoY());
                dto.setMercatorX(mapPoint.x);
                dto.setMercatorY(mapPoint.y);
            }
            //todo 设置案件办理时限,每个案件类型可在pmi配置不同的时限，每个环节可在环节定义中配置不同的时限（目前pmi的相关接口存在问题）
            // 需注意：案件类型对应的时限是整个案件的总时限，配置多个环节的时限总和不应超过这个总时限。
            if ((dto.getHandleLimit() == null || dto.getHandleLimit() == 0) && CollectionUtils.isNotEmpty(dto.getTypeList())) {
                dto.setHandleLimit(sysClassExtLogic.getEntityByDataId(dto.getTypeList().get(dto.getTypeList().size() - 1)).limit);
            }
            if (dto.getHandleLimit() == null || dto.getHandleLimit() == 0) {
                dto.setHandleLimit(86400);//默认限时一天，
                dto.setShouldFinishedTime(LocalDateTime.now().plusSeconds(dto.getHandleLimit()));
            }
            if (StringUtils.isBlank(dto.getEvtId())) {
                dto.setEvtId(UUID.randomUUID().toString().toUpperCase());
            }
            EventInfo eventInfo = mapper.map(dto, EventInfo.class);
            if (CollectionUtils.isNotEmpty(dto.getTypeList())) {
                eventInfo.setTypeId(StringUtils.join(dto.getTypeList(), ","));
            }
            //启动流程
            StartResult startResult = workFlowUtil.startHwWorkFlow(eventInfo.getReportId(), eventInfo.getReportName());
            if (startResult == null || !startResult.isSuccess()) {
                return JsonResult.error("案件流程启动失败");
            }
            eventInfo.setWfInstId(startResult.getWorkflowInstanceId());
            ActivityInstance activityInstance = startResult.getInstance();
            //保存附件记录
            if (CollectionUtils.isNotEmpty(dto.getFileList())) {
                List<EventInfoFile> eventInfoFiles = buildEvtFile(dto.getFileList(), eventInfo.getEvtId(), eventInfo.getReportId(), activityInstance.activityInstanceId, fileDataType.get(activityInstance.activityIdentifier));
                if (CollectionUtils.isNotEmpty(eventInfoFiles)) {
                    eventInfo.setPhotoId(eventInfoFiles.get(0).getFileId());
                    eventInfoFileDao.insert(eventInfo.getReportId(), eventInfoFiles);
                }
            }
            //生成案件号
            SerialNoDTO serialNo = eventInfoDao.getEvtCode(String.valueOf(LocalDateTime.now().getYear()), null, "t_event_info");
            if (serialNo == null || StringUtils.isBlank(serialNo.getTitle())) {
                return JsonResult.error("案件号生成失败");
            }
            log.info("年份：{}，生成的案件号：{}----序号：{}", LocalDateTime.now().getYear(), serialNo.getTitle(), serialNo.getSerialNo());
            eventInfo.setCode(serialNo.getTitle());
            if (StringUtils.isNotBlank(eventInfo.getLastDeptId())) {
                SingleResult autoReportResult = workFlowUtil.sendToNextActivity(
                        dto.getReportId(),
                        dto.getReportName(),
                        activityInstance.activityInstanceId,
                        EventFlowConfig.sendId,
                        "系统自动发送",
                        0,
                        deptLogic.getDeptName("CBB2548D-8E65-4A04-9752-0388E8A2CCD7"),
                        "CBB2548D-8E65-4A04-9752-0388E8A2CCD7",//派遣部门
                        ReceiveTypeEnum.DEPT,
                        null,//处理时限由各环节自行配置
                        false);
                if (autoReportResult == null || !autoReportResult.isSuccess) {
                    return JsonResult.error("自动上报异常！");
                }
                ActivityInstance curInstance = autoReportResult.getInstance();
                eventInfo.setCurActId(curInstance.activityInstanceId)
                        .setCurActName(curInstance.activityName)
                        .setCurActTime(curInstance.inDate)
                        .setStatus(0)
                        .setAuditResult((byte) 0);
                //如果选择了处置企业，则自动派遣到处置单位，如果是案件类型是 其他任务 则需自动派遣到执行人
                if (eventInfo.getCompanyId() != null) {
                    SingleResult autoSendResult;
                    if (!dto.getTypeList().contains("1B3E5DD2-7DFE-4C0B-A546-C6076CCDF6BB")) {
                        SysCompany disposeCompany = companyLogic.getEntity(eventInfo.getCompanyId());
                        autoSendResult = workFlowUtil.sendToNextActivity(
                                eventInfo.getReportId(), eventInfo.getReportName(), curInstance.activityInstanceId, EventFlowConfig.disposalId, "系统自动派遣",
                                (int) Duration.between(curInstance.inDate, LocalDateTime.now()).getSeconds(),
                                disposeCompany.name, disposeCompany.companyId, ReceiveTypeEnum.DEPT, null, false);
                    } else {//其他任务
                        autoSendResult = workFlowUtil.sendToNextActivity(
                                eventInfo.getReportId(), eventInfo.getReportName(), curInstance.activityInstanceId, EventFlowConfig.disposalId, "系统自动派遣",
                                (int) Duration.between(curInstance.inDate, LocalDateTime.now()).getSeconds(),
                                dto.getExecutor(), dto.getExecutorId(), ReceiveTypeEnum.USER, null, false);
                    }
                    if (autoSendResult == null || !autoSendResult.isSuccess) {
                        return JsonResult.error("自动派遣异常！");
                    }
                    ActivityInstance sendInstance = autoSendResult.getInstance();
                    eventInfo.setCurActId(sendInstance.activityInstanceId)
                            .setCurActName(sendInstance.activityName)
                            .setCurActTime(sendInstance.inDate);
                }
                eventInfoDao.insert(eventInfo.getReportId(), eventInfo);//保存案件信息
            }
            return JsonResult.ok(serialNo.getTitle());
        } catch (Exception e) {
            e.printStackTrace();
            return JsonResult.error("案件生成异常");
        }
    }

    private List<EventInfoFile> buildEvtFile(List<EventInfoFile> fileList, String evtId, String reportId, String activityInstanceId, Integer dataType) {
        return fileList.stream().peek(eventInfoFile -> {
            eventInfoFile.setCreateId(reportId);
            eventInfoFile.setEvtId(evtId);
            eventInfoFile.setActInstId(activityInstanceId);
            eventInfoFile.setDataType(dataType);
            eventInfoFile.setFileName(StringUtils.isNotBlank(eventInfoFile.getFileName()) ? eventInfoFile.getFileName() : String.format("%s.jpg", UUID.randomUUID().toString()));
            eventInfoFile.setFileType(StringUtils.isNotBlank(eventInfoFile.getFileType()) ? eventInfoFile.getFileType() : eventInfoFile.getFileName().substring(eventInfoFile.getFileName().lastIndexOf(".")));
        }).collect(Collectors.toList());
    }

    @Transactional
    public JsonResult<?> processEvent(SysUser user, SendActPara sendActPara) {
        try {
            sendActPara.setUserId(user.userId).setUserName(user.userName).setReceiverType(ReceiveTypeEnum.DEPT);
            EventInfo eventInfo = eventInfoDao.getEntityByColumn("c_evt_id", sendActPara.getEvtId());
            if (eventInfo == null) {
                return JsonResult.error("办理案件不存在");
            }
            CheckResult checkResult = workflowRuntimeManager.checkActivityAlive(sendActPara.getCurActInstId(), sendActPara.getUserId());
            if (!checkResult.isSuccess) {
                return JsonResult.error("该环节已办理,请刷新待办列表");
            }
            ActivityInstanceBo instanceBo = checkResult.getInstance();
            //如果当前用户不是管理员，则需校验当前用户是否有办理当前流程的权限(判断当前用户是否属于环节接收部门)
            if (user.userIsAdmin != 1) {
                if (instanceBo.receiveTypeId == 100603) {
                    List<DeptDto> authDeptList = deptUtil.getAuthDeptList(user);
                    if (CollectionUtils.isEmpty(authDeptList)) {
                        return JsonResult.error("当前用户没有办理权限！");
                    }
                    long count = authDeptList.stream().filter(dept -> dept.deptId.equals(instanceBo.receiveObjectId)).count();
                    if (count < 1) {
                        return JsonResult.error("当前用户没有办理权限！");
                    }
                }
                if (instanceBo.receiveTypeId == 100601 && !user.userId.equals(instanceBo.receiveObjectId)) {
                    return JsonResult.error("当前用户没有办理权限！");
                }
            }
            // 计算环节用时 当前处理时间
            LocalDateTime now = LocalDateTime.now();
            sendActPara.setUsedTime((int) Duration.between(instanceBo.inDate, now).getSeconds())
                    .setUserId(sendActPara.getUserId())
                    .setUserName(sendActPara.getUserName())
                    .setDealTime(now);
            //保存办理的附件
            if (CollectionUtils.isNotEmpty(sendActPara.getFileList())) {
                List<EventInfoFile> eventInfoFiles = buildEvtFile(sendActPara.getFileList(),
                        sendActPara.getEvtId(),
                        sendActPara.getUserId(),
                        sendActPara.getCurActInstId(),
                        fileDataType.get(instanceBo.getActivityData().getIdentifier()));
                eventInfoFileDao.insert(sendActPara.getUserId(), eventInfoFiles);
            }
            SingleResult singleResult = workFlowUtil.sendToNextActivity(sendActPara);
            ActivityInstance instance = singleResult.getInstance();
            eventInfo.setCurActId(instance.activityInstanceId)
                    .setCurActName(instance.activityName)
                    .setCurActTime(instance.inDate)
                    .setStatus(1);
            String activityIdentifier = sendActPara.getActivityIdentifier();//环节标识
            if (activityIdentifier.equalsIgnoreCase(EventFlowConfig.disposalId)) {//如果是案件派遣，更新处置部门
                SysCompany disposeCompany = companyLogic.getEntityByDataId(sendActPara.getReceiverId());
                eventInfo.setCompanyId(disposeCompany.id);
            }
            if (activityIdentifier.equalsIgnoreCase(EventFlowConfig.endId)) {//如果是案件审核，要更新案件审核情况,且结束案件
                eventInfo.setAuditResult((byte) 1)//默认审核通过
                        .setAuditDate(now)
                        .setAuditOptions(sendActPara.getContent())//办理意见即为审核意见
                        .setStatus(2)//案件结束
                        .setFinishedTime(instance.inDate)
                        .setIsKf((byte) 1);//确认扣分
            }
            this.update(sendActPara.getUserId(), eventInfo);
            return JsonResult.ok(singleResult);
        } catch (Exception e) {
            e.printStackTrace();
            return JsonResult.error("办理出错");
        }
    }

    @Autowired
    private EventFlowConfig eventFlowConfig;

    @PostConstruct
    public void init() {
        fileDataType.put(eventFlowConfig.reportId, 1);
        fileDataType.put(eventFlowConfig.sendId, 2);
        fileDataType.put(eventFlowConfig.disposalId, 3);
        fileDataType.put(eventFlowConfig.auditId, 4);
        fileDataType.put(eventFlowConfig.endId, 5);
    }

    private final Map<String, Integer> fileDataType = new HashMap<String, Integer>();

    public DataPager<EventInfoVO> getEventTodoList(EventInfoQuery query, SysUser user) {
        //非管理员，只允许在代办列表中看到有权办理的案件
        List<String> receiveObjectIds = deptUtil.setAuthDeptList(user);
        if (user.userIsAdmin != 1 && CollectionUtils.isEmpty(receiveObjectIds)) {
            return null;
        }
        if (CollectionUtils.isNotEmpty(receiveObjectIds)) {
            //如果环节接收对象是人，则查询条件应加上
            receiveObjectIds.add(user.userId);
        }
        DataPager<EventInfoVO> resultPage = eventInfoDao.listPage(query, user, receiveObjectIds);
        resultPage.records = resultPage.records.stream().map(evt ->
                CompletableFuture.supplyAsync(() -> {
                    List<EventInfoFile> files = eventInfoFileDao.getEntitiesByOneColumn(new KeyValue<>("c_evt_id", evt.getEvtId()));
                    evt.setFileList(files);
                    setType(evt);
                    return evt;
                })
        ).collect(Collectors.toList()).stream().map(CompletableFuture::join).collect(Collectors.toList());
        return resultPage;
    }

    private void setType(EventInfoVO evt) {
        if (StringUtils.isNotBlank(evt.getTypeId())) {
            List<String> typeIdList = Arrays.stream(evt.getTypeId().split(",")).collect(Collectors.toList());
            evt.setTypeList(typeIdList);
            List<Map<String, Object>> classList = eventInfoDao.getSysClassList(typeIdList);
            if (CollectionUtils.isNotEmpty(classList)) {
                StringBuilder typeName = new StringBuilder();
                for (int i = 0; i < classList.size(); i++) {
                    typeName.append(classList.get(i).getOrDefault("typeName", ""));
                    if (i < classList.size() - 1) {
                        typeName.append("/");
                    }
                }
                evt.setTypeName(typeName.toString());
            }
        }
    }

    public JsonResult<?> getToDoEventDetail(String evtId, String curActId, String userId) throws Exception {
        CheckResult checkResult = workflowRuntimeManager.checkActivityAlive(curActId, userId);
        if (!checkResult.isSuccess) {
            return JsonResult.error("该环节已被办理,请刷新您的待办列表！");
        }
        EventInfoVO eventInfoVO = eventInfoDao.getEventDetail(new EventInfoQuery(evtId, null, null, null, null, null, null));
        setType(eventInfoVO);//设置类型属性
        List<EventInfoFile> files = eventInfoFileDao.getEntitiesByOneColumn(new KeyValue<>("c_evt_id", evtId));
        eventInfoVO.setFileList(files);
        if (StringUtils.isNotBlank(eventInfoVO.getPrevActInstId())) {
            ActivityInstanceBo activityInstance = workflowRuntimeManager.getActivityInstance(eventInfoVO.getPrevActInstId());
            if (activityInstance != null) {
                eventInfoVO.setPrevActInstName(activityInstance.activityName);
                eventInfoVO.setPrevActInstContent(activityInstance.content);
            }
            eventInfoVO.setCanUntrend(checkResult.getInstance().getActivityData().getIsUntread());
        }
        return JsonResult.ok(eventInfoVO);
    }

    public JsonResult<?> getNextActivity(String actInstId, Integer sectionId) {
        try {
            List<RuntimeActivity> runtimeActivities = workflowRuntimeManager.getNextActivityCollection(actInstId);
            List<NextActivityTarget> nextActivityTargetList = new ArrayList<>();
            runtimeActivities.forEach(activity -> {
                NextActivityTarget item = new NextActivityTarget();
                item.setActIdentifyId(activity.getIdentifier());
                item.setActIdentifyName(activity.getName());
                List<Target> targets = new ArrayList<>();
                if (item.getActIdentifyId().equals(EventFlowConfig.sendId)) {//派遣单位
                    setProcessor("666AA654-46C9-4070-8CBA-DD38F5F2373F", targets);
                } else if (item.getActIdentifyId().equals(EventFlowConfig.disposalId)) {//处置单位
                    setProcessor("CC0E1876-8C41-41FA-9421-27D0528A3D08", targets);
                    //此处应业务特殊需求，处置环节 对象必须为新增时拟定标段下的企业
                    CompanyQuery query = new CompanyQuery();
                    query.setSectionId(sectionId.toString());
                    List<String> companyIdList = parkCompanyLogic.getShortList(query).stream().map(m -> m.get("companyId").toString()).collect(Collectors.toList());
                    targets = targets.stream().filter(target -> companyIdList.contains(target.getId())).collect(Collectors.toList());
                } else if (item.getActIdentifyId().equals(EventFlowConfig.auditId)) {//审核单位
                    setProcessor("74F50BD3-66B2-4A06-9E27-98DD03168183", targets);
                }
                if (item.getActIdentifyId().equals(EventFlowConfig.endId)) {
                    Target target = new Target();
                    target.setId("0");
                    target.setName("结束");
                    target.setTypeEnum(ReceiveTypeEnum.OTHER);
                    targets.add(target);
                }
                item.setTargets(targets);
                nextActivityTargetList.add(item);
            });
            return JsonResult.ok(nextActivityTargetList);
        } catch (Exception e) {
            e.printStackTrace();
            return JsonResult.error(e.getMessage());
        }
    }

    private List<Target> setProcessor(String treeId, List<Target> targets) {
        List<DeptInTreeDto> inTreeList = sysDeptInTreeLogic.getInTreeList(treeId);
        List<DeptInTreeDto> rootMenus = findSysDept(inTreeList, SystemConst.UUID_EMPTY_STRING);
        List<DeptTree> treeList = new ArrayList<>();
        for (DeptInTreeDto m : rootMenus) {
            DeptTree node = new DeptTree();
            node.setId(m.deptId);
            node.setParentId(m.deptPid);
            node.setLabel(m.getDeptName());
            node.setSortCode(m.orderNum);
            node.setValue(m.deptId);
            node.setChildren(new ArrayList<>());
            buildChildrenDept(inTreeList, node);
            treeList.add(node);
        }
        for (DeptTree s : treeList) {
            Target target = new Target();
            target.setId(s.getId());
            target.setName(s.getLabel());
            target.setRefId("0");
            target.setTypeEnum(ReceiveTypeEnum.DEPT);
            targets.add(target);
        }
        targets = targets.stream()
                .sorted(Comparator.comparing(Target::getRefId))
                .collect(Collectors.toList());
        return targets;
    }

    private void buildChildrenDept(List<DeptInTreeDto> dataSource, DeptTree parentNode) {
        List<DeptInTreeDto> nodes = findSysDept(dataSource, parentNode.getId());
        for (DeptInTreeDto m : nodes) {
            DeptTree node = new DeptTree();
            node.setId(m.deptId);
            node.setParentId(m.deptPid);
            node.setLabel(m.getDeptName());
            node.setSortCode(m.orderNum);
            node.setValue(m.deptId);
            node.setChildren(new ArrayList<>());
            buildChildrenDept(dataSource, node);
            parentNode.getChildren().add(node);
        }
    }

    private List<DeptInTreeDto> findSysDept(List<DeptInTreeDto> dataSource, String menuId) {
        List<DeptInTreeDto> newMenuList = new ArrayList<>();
        for (DeptInTreeDto menu : dataSource) {
            if (ObjectUtils.isNotEmpty(menu.deptPid) && menu.deptPid.equals(menuId)) {
                newMenuList.add(menu);
            }
        }
        return newMenuList;
    }

    public DataPager<EventInfoVO> getEventSearchList(EventInfoQuery query, SysUser user) {
        List<String> receiveObjectIds = deptUtil.setAuthDeptList(user);
        if (user.userIsAdmin != 1 && CollectionUtils.isEmpty(receiveObjectIds)) {
            return null;
        }
        if (CollectionUtils.isNotEmpty(receiveObjectIds)) {
            //如果环节接收对象是人，则查询条件应加上
            receiveObjectIds.add(user.userId);
        }
        DataPager<EventInfoVO> page = eventInfoDao.getEvtSearchPage(query, user, receiveObjectIds);
        page.records.forEach(vo -> {
            setType(vo);
            vo.setFileList(eventInfoFileDao.getEntitiesByOneColumn(new KeyValue<>("c_evt_id", vo.getEvtId())));
        });
        return page;
    }

    public JsonResult<?> checkUntreadActivity(BackActPara para) {
        try {
            BackPara backPara = new BackPara();
            backPara.setCurrentInstId(para.getCurInstId());
            backPara.setContent(para.getContent());
            backPara.setDate(LocalDateTime.now());
            backPara.setUserId(para.getUserId());
            backPara.setUserName(para.getUserName());
            SingleResult singleResult = workflowRuntimeManager.untreadActivity(backPara);
            if (singleResult.isSuccess) {
                //更新案件当前环节
                ActivityInstance instance = singleResult.getInstance();
                List<KeyValue> setList = new ArrayList<KeyValue>() {
                    {
                        add(new KeyValue("c_cur_act_id", instance.activityInstanceId));
                        add(new KeyValue("c_cur_act_name", instance.activityName));
                        add(new KeyValue("c_cur_act_time", instance.inDate));
                    }
                };
                eventInfoDao.updateByColumns(para.getUserId(), setList, Collections.singletonList(new KeyValue<>("c_evt_id", para.getEvtId())));
                return JsonResult.ok(singleResult.getErrorMessage());
            } else {
                return JsonResult.error(singleResult.getErrorMessage());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return JsonResult.error(e.getMessage());
        }
    }

    public DataPager<EventInfoVO> getFinishedEventList(EventInfoQuery query, SysUser user) {
        query.setStatus(2);
        List<String> receiveObjectIds = deptUtil.setAuthDeptList(user);
        if (user.userIsAdmin != 1 && CollectionUtils.isEmpty(receiveObjectIds)) {
            return null;
        }
        if (CollectionUtils.isNotEmpty(receiveObjectIds)) {
            //如果环节接收对象是人，则查询条件应加上
            receiveObjectIds.add(user.userId);
        }
        DataPager<EventInfoVO> page = eventInfoDao.getEvtSearchPage(query, user, receiveObjectIds);
        page.records.forEach(vo -> {
            setType(vo);
            vo.setFileList(eventInfoFileDao.getEntitiesByOneColumn(new KeyValue<>("c_evt_id", vo.getEvtId())));
        });
        return page;
    }

    public List<ActivityInstanceVO> getFlowsByIds(String wfInstId, String evtId) {
        List<ActivityInstance> activityInstances = workflowRuntimeManager.getActivityInstanceList(wfInstId);
        // 案件附件
        List<EventInfoFile> eventFiles = eventInfoFileDao.getEntitiesByOneColumn(new KeyValue<>("c_evt_id", evtId));
        List<ActivityInstanceVO> actInstTargetList = activityInstances.stream().map(item -> {
            ActivityInstanceVO targetItem = new ActivityInstanceVO();
            DataFillHelper.readToTarget(item, targetItem);
            targetItem.limitStr = Utility.GetTimeString(item.limit);
            if (CollectionUtils.isNotEmpty(eventFiles)) {
                targetItem.taskFiles = eventFiles.stream().filter(fileItem -> StringUtils.isNotEmpty(fileItem.getActInstId())
                        && fileItem.getActInstId().equalsIgnoreCase(targetItem.activityInstanceId)).collect(Collectors.toList());
                targetItem.attachCount = targetItem.taskFiles.size();
            }
            // 针对有时限的环节计算是否超时
            if (targetItem.limit > 0) {
                int usedTimeSeconds = (int) Math.abs(Duration.between(targetItem.inDate, targetItem.finishedDate == null ? LocalDateTime.now() : targetItem.finishedDate).toMillis() / 1000);
                targetItem.isTimeout = (byte) (usedTimeSeconds - targetItem.limit >= 0 ? 1 : 0);
                targetItem.usedTime = usedTimeSeconds;
                targetItem.usedTimeStr = Utility.GetTimeString(usedTimeSeconds);
                targetItem.outTime = usedTimeSeconds - targetItem.limit;
                targetItem.outTimeStr = targetItem.outTime > 0 ? "超时" + Utility.GetTimeString(targetItem.outTime) : "剩余" + Utility.GetTimeString(targetItem.outTime);
            } else {
                int usedTimeSeconds = (int) Math.abs(Duration.between(targetItem.inDate, targetItem.finishedDate == null ? LocalDateTime.now() : targetItem.finishedDate).toMillis() / 1000);
                targetItem.usedTime = usedTimeSeconds;
                targetItem.usedTimeStr = Utility.GetTimeString(usedTimeSeconds);
                targetItem.outTime = 0;
                targetItem.outTimeStr = "- -";
            }
            return targetItem;
        }).collect(Collectors.toList());
        return actInstTargetList;
    }

    public JsonResult<?> updateEvent(String userId, EventInfoBo eventInfoBo) {
        try {
            eventInfoBo.setUserId(userId);
            CheckResult checkResult = workflowRuntimeManager.checkActivityAlive(eventInfoBo.getCurActInstId(), eventInfoBo.getUserId());
            if (!checkResult.isSuccess) {
                return JsonResult.error("该环节已办理,请刷新待办列表");
            }
            if (eventInfoBo.getGeoX() != null && eventInfoBo.getGeoY() != null) {
                PointDto pointDto = CoordinateTransHelper.gcjDecrypt(eventInfoBo.getGeoX(), eventInfoBo.getGeoY());
                PointDto baidu = CoordinateTransHelper.wgs84Bd09(pointDto.getLng(), pointDto.getLat());
                eventInfoBo.setLngBd09(baidu.getLng());
                eventInfoBo.setLatBd09(baidu.getLat());
            }
            if (eventInfoBo.getLngBd09() != null && eventInfoBo.getLatBd09() != null) {
                PointDto pointDto = CoordinateTransHelper.bdDecrypt(eventInfoBo.getLngBd09(), eventInfoBo.getLatBd09());
                eventInfoBo.setGeoX(pointDto.getLng());
                eventInfoBo.setGeoY(pointDto.getLat());
            }
            if (eventInfoBo.getGeoX() != null && eventInfoBo.getGeoY() != null) {
                GeometryHelper.MapPoint mapPoint = GeometryHelper.xyToMercator(eventInfoBo.getGeoX(), eventInfoBo.getGeoY());
                eventInfoBo.setMercatorX(mapPoint.x);
                eventInfoBo.setMercatorY(mapPoint.y);
            }
            EventInfo targetEvent = eventInfoDao.getEntityByColumn("c_evt_id", eventInfoBo.getEvtId());
            BeanUtil.copyProperties(eventInfoBo, targetEvent);
            if (CollectionUtils.isNotEmpty(eventInfoBo.getTypeList())) {
                targetEvent.setTypeId(StringUtils.join(eventInfoBo.getTypeList(), ","));
            }
//            String curActId = targetEvent.getCurActId();
            //删除上一环节附件
            ActivityInstanceBo instance = checkResult.getInstance();
            if (StringUtils.isBlank(instance.prevActivityInstanceId)) {
                return JsonResult.error("上一环节为空，错误案件！");
            }
            eventInfoFileDao.deleteLastActFile(eventInfoBo.getEvtId(), instance.prevActivityInstanceId);
            if (CollectionUtils.isNotEmpty(eventInfoBo.getFileList())) {
                //保存新的附件
                List<EventInfoFile> files = buildEvtFile(eventInfoBo.getFileList(), eventInfoBo.getEvtId(), userId, instance.prevActivityInstanceId, fileDataType.get(instance.prevInst.activityIdentifier));
                eventInfoFileDao.insert(eventInfoBo.getUserId(), files);
            }
            eventInfoDao.update(userId, targetEvent);
            return JsonResult.ok(true);
        } catch (Exception e) {
            e.printStackTrace();
            return JsonResult.error("修改出现错误！");
        }
    }

    public EventInfoVO getInfoById(Integer id) {
        EventInfoVO vo = eventInfoDao.getInfoById(id);
        if (vo == null) {
            return null;
        }
        vo.setFileList(eventInfoFileDao.getEntitiesByOneColumn(new KeyValue<>("c_evt_id", vo.getEvtId())));
        setType(vo);
        return vo;
    }

    /**
     * @param { "actInstId": "602211AA-F666-4A08-B9AE-A1922219241B",
     *          "evtId": "EC8C7B3E-28DD-45B4-AC0E-A8B79B598D86",
     *          "reqLimit": 5000,
     *          "reqReason": "KFC Crazy Thursday, Can you v me 50$",
     *          "reqType": 0,
     *          "selfDefLimit": 8000
     *          }
     */
    @Transactional
    public JsonResult<?> eventDelayApply(EventDelayApplyDTO para) {
        try {
            CheckResult checkResult = workflowRuntimeManager.checkActivityAlive(para.getActInstId(), para.getUserId());
            if (!checkResult.isSuccess) {
                return JsonResult.error("该环节已办理,请刷新待办列表");
            }
            ActivityInstanceBo activityInstance = checkResult.getInstance();
            para.setDelayId(UUID.randomUUID().toString().toUpperCase())
                    .setReqUserId(para.getUserId())
                    .setReqDate(LocalDateTime.now())
                    .setReqUserDepId(para.getDeptId())
                    .setReqLimit(para.getReqLimit() * 3600)
                    .setSelfDefLimit(para.getSelfDefLimit() * 3600)
                    .setOldLimit(ObjectUtils.isNotEmpty(activityInstance.shouldFinishedDate) ? (int) Duration.between(activityInstance.inDate, activityInstance.shouldFinishedDate).getSeconds() : 7200)
                    .setNewLimit(para.getOldLimit() + para.getReqLimit());
            JsonResult<String> result = eventDelayApplyLogic.eventDelayApply(para);
            if (result.success) {
                return JsonResult.ok("延时申请已发出！");
            } else {
                return JsonResult.error(result.msg);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return JsonResult.error("延时申请异常");
        }
    }

    @Transactional
    public JsonResult<?> eventDelayAudit(SysUser user, EventDelayAuditDTO dto) {
        try {
            dto.setAuditUserId(user.userId);
            //更新延时申请表信息
            EventDelayApply entity = eventDelayApplyLogic.getEntityByColumnEqValue(new KeyValue<>("c_delay_id", dto.getDelayId()));
            entity.auditDate = LocalDateTime.now();
            BeanUtil.copyProperties(dto, entity);
            eventDelayApplyLogic.update(user.userId, entity);
            //审核通过则修改环节时限，以及案件时限
            if (dto.getIsPass() == 1) {
                ActivityInstanceBo activityInstance = workflowRuntimeManager.getActivityInstance(entity.actInstId);
                workflowRuntimeManager.updateActivityInstanceLimit(entity.actInstId, entity.newLimit, activityInstance.inDate.plusSeconds(entity.newLimit));
                if (entity.selfDefLimit != null) {
                    eventInfoDao.addShouldFinishTime(entity.selfDefLimit);
                }
            }
            return JsonResult.ok("延时审核完成");
        } catch (Exception e) {
            e.printStackTrace();
            return JsonResult.error("审核出现异常！");
        }
    }

    public DataPager<EventDelayApplyVO> getEventDelayApplyList(EventDelayApplyQuery query) {
        return eventDelayApplyLogic.getEventDelayApplyList(query);
    }

    public List<Map<String, Object>> eventCount(String dateFormat, String timeSlot) {
        return eventInfoDao.eventCount(dateFormat, timeSlot);
    }

    public List<Map<String, Object>> getEventTaskCount() {
        return eventInfoDao.getEventTaskCount();
    }

    public DataPager<EventInfoVO> getOwnEventPage(Integer pageIndex, Integer pageSize) {
        EventInfoQuery query = new EventInfoQuery();
        query.pageIndex = pageIndex;
        query.pageSize = pageSize;
        query.setReportId(UserRuntime.getSysUser().userId);
        return eventInfoDao.getEvtSearchPage(query, null, null);
    }
}
